from django import template
from django import forms
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
import datetime
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from pirate_core import HttpRedirectException, namespace_get, FormMixin
from pirate_issues.models import Problem, Solution
from pirate_consensus.models import UpDownVote, Consensus
from django.utils.translation import ugettext as _
from pirate_reputation.models import ReputationDimension
from pirate_core.helpers import clean_html
from pirate_signals.models import relationship_event

from pirate_signals.models import aso_rep_event, notification_send

from customtags.decorators import block_decorator
register = template.Library()
block = block_decorator(register)

'''
This file contains all of the tags that pertain to Issue objects, in order to fetch one
issue, a list of issues, or to add or update an issue.
'''


# this function assignment lets us reuse the same code block a bunch of places
get_namespace = namespace_get('pp_solution')


@block
def pp_get_solution(context, nodelist, *args, **kwargs):
    '''
    This block tag will grab an issue based on an object passed in
    as an argument (assigned to object), and will then put that solution into the context.

    The (str, obj_id) pair will be available via request.object.  In order to populate 
    request.objcect, the page in question should be accessed by via a url created as follows:

    {% pp_url object=solution template="filename.html" %}
    '''

    context.push()
    namespace = get_namespace(context)

    # this tag only works if a valid pair is assigned to the 'object=' argument
    object = kwargs.pop('object', None)
    if object is None:
        raise ValueError("pp_get_solution tag requires that a object be passed "
                             "to it assigned to the 'object=' argument")
    
    namespace['solution'] = object
    
    #grab consensus objects and votes related to this issue
    namespace['consensus'] = get_object_or_404(Consensus,object_pk=object.id)
    namespace['upvotes'] = len(UpDownVote.objects.filter(parent=namespace['consensus'],vote_type=1))
    namespace['downvotes'] = len(UpDownVote.objects.filter(parent=namespace['consensus'],vote_type=-1))
    namespace['neutralvotes'] = len(UpDownVote.objects.filter(parent=namespace['consensus'],vote_type=0))
    
    output = nodelist.render(context)
    context.pop()

    return output

@block
def pp_get_solution_list(context, nodelist, *args, **kwargs):

    """ pp_get_solution_list retrieves list of solutions that can be filtered by issue"""

    context.push()
    namespace = get_namespace(context)

    #user  = kwargs.pop('user',  None)        solution_list = solution_list.filter(issue__id=issue.id)
    dimension = kwargs.pop('dimension',None)
    issue = kwargs.pop('issue', None)
    rng = kwargs.pop('rng',None)

    if isinstance(rng, basestring):
        try:
            rng = rng.strip("()").split(",")
            rng = (int(rng[0]), int(rng[1]))
        except:
            rng = None

        if not rng or len(rng) != 2:
            raise ValueException("The argument 'rng=' to the pp-issue-list tag must be "
                                 "provided either in the form of an (int, int) pair, or "
                                 "as a string in the form of '(<int>, <int>)'.")
                                 
    content_type = ContentType.objects.get_for_model(Solution)
    solution_list = Solution.objects.filter(issue=issue)
    consensus_list = Consensus.objects.all()
    consensus_list = consensus_list.filter(content_type=content_type)
    adjust_for_range = True
    if not rng: #need to add a range if not specified.
        rng = (0,20)

    if issue and isinstance(issue, Issue):
        solution_list = solution_list.filter(issue__id=issue.id)
        topic = issue.topic
        
    elif issue and isinstance(issue, Solution):
        solution_list = solution_list.filter(issue__id=issue.issue.id)
        topic = issue.issue.topic
    elif issue == None:
        topic = None
        
    #TODO: OPTIMIZE THIS!!!
   
    if dimension == "new":
        order_by = '-submit_date'
    elif dimension == "hot" or dimension == None: #default case
        order_by = '-interest'
    elif dimension == "cont":
        order_by = '-controversy'
    elif dimension == "top":
        order_by = '-votes' 
        
    if issue and isinstance(issue, Issue): consensus_list = consensus_list.filter(parent_pk=issue.pk)
        
    solution_list = consensus_list.order_by(order_by) 
      
    try: namespace['count'] = solution_list.count()
    except: namespace['count'] = 0
    
    if adjust_for_range: #filter for rng
        solution_list = solution_list[rng[0]:rng[1]]
        
    namespace['solution_list'] = solution_list
    output = nodelist.render(context)
    context.pop()

    return output


@block
def pp_solution_form(context, nodelist, *args, **kwargs):


    context.push()
    namespace = get_namespace(context)

    POST  = kwargs.get('POST', None)
    path  = kwargs.get('path', None)
    obj = kwargs.get('object',None)
    user = kwargs.get('user',None)
    request = kwargs.get('request',None)

    #generate path to this solution
        

    #print POST
    #print request
    if obj and isinstance(obj, Issue):
        issue = obj
        solution = None
    elif obj and isinstance(obj,Solution):
        solution = obj
        issue = solution.issue
    if POST and POST.get("form_id") == "pp_solution_form":
        form = SolutionForm(POST) if solution is None else SolutionForm(POST, instance=solution)
        if form.is_valid():   
            new_sol = form.save(commit=False)                 
            new_sol.submit_date = datetime.datetime.now()
            new_sol.issue = issue
            new_sol.text = clean_html(new_sol.text)
            new_sol.name = clean_html(new_sol.name)
            new_sol.comments = 0
            new_sol.arguments = 0
            new_sol.user = request.user
            new_sol.save()

            contype = ContentType.objects.get_for_model(Solution)
            obj_pk  = new_sol.pk
            cons, is_new = Consensus.objects.get_or_create(content_type=contype,
                                                               object_pk=obj_pk,
                                                               parent_pk=issue.pk)
                            
            if is_new: #if this is a new issue/consensus, send signal for reputation
                aso_rep_event.send(sender=new_sol,event_score=5, user=new_sol.user, dimension=ReputationDimension.objects.get('Solution Author'))
                notification_send.send_robust(sender=new_sol.user,obj=new_sol,reply_to=new_sol.issue)
                relationship_event.send(sender=new_sol,obj=new_sol,parent=new_sol.issue)
                issue.solutions = issue.solutions+1
                issue.save()
            raise HttpRedirectException(HttpResponseRedirect(new_sol.get_absolute_url()))

            path = new_sol.get_absolute_url()
            raise HttpRedirectException(HttpResponseRedirect(path))
        else: namespace['errors'] = form.errors
            
        
    else:
        form = SolutionForm() if solution is None else SolutionForm(instance=solution)

            
    namespace['form'] = form
    output = nodelist.render(context)
    context.pop()

    return output


class SolutionForm(forms.ModelForm, FormMixin):
    '''
    This form is used to allow creation and modification of solution objects.  
    It extends FormMixin in order to provide a create() class method, which
    is used to process POST, path, and object variables in a consistant way,
    and in order to automatically provide the form with a form_id.
    '''

    def save(self, commit=True):
        new_solution = super(SolutionForm, self).save(commit=commit)
            
        return new_solution

    class Meta:
        model = Solution
        exclude = ('issue','user','comments','arguments')

    form_id = forms.CharField(widget=forms.HiddenInput(), initial="pp_solution_form")
    text = forms.CharField(widget=forms.Textarea)
    name = forms.CharField(label="text", max_length=100,
              widget=forms.TextInput( 
                attrs={'size':'50', 'class':'inputText'})) 
    #comments = forms.CharField(widget=forms.HiddenInput(), initial=0)
    #issue = forms.CharField(widget=forms.HiddenInput(), initial=None)
    #user = forms.CharField(widget=forms.HiddenInput(), initial=None) 
